﻿#include "StdAfx.h"
#include "UIFlash.h"
#include <atlcomcli.h>

#define DISPID_FLASHEVENT_FLASHCALL	 ( 0x00C5 )
#define DISPID_FLASHEVENT_FSCOMMAND	 ( 0x0096 )
#define DISPID_FLASHEVENT_ONPROGRESS	( 0x07A6 )

namespace DuiLib {
	IMPLEMENT_DUICONTROL (CFlashUI)

		CFlashUI::CFlashUI (void) {
		faw::String strFlashCLSID = _T ("{D27CDB6E-AE6D-11CF-96B8-444553540000}");
		OLECHAR szCLSID[100] = { 0 };
#ifndef _UNICODE
		::MultiByteToWideChar (::GetACP (), 0, strFlashCLSID, -1, szCLSID, lengthof (szCLSID) - 1);
#else
		_tcsncpy (szCLSID, strFlashCLSID.c_str (), lengthof (szCLSID) - 1);
#endif
		::CLSIDFromString (szCLSID, &m_clsid);
	}

	CFlashUI::~CFlashUI (void) {
		if (m_pFlashEventHandler) {
			m_pFlashEventHandler->Release ();
			m_pFlashEventHandler = nullptr;
		}
		ReleaseControl ();
	}

	faw::string_view_t CFlashUI::GetClass () const {
		return DUI_CTRL_FLASH;
	}

	LPVOID CFlashUI::GetInterface (faw::string_view_t pstrName) {
		if (pstrName == DUI_CTRL_FLASH) return static_cast<CFlashUI*>(this);
		return CActiveXUI::GetInterface (pstrName);
	}

	HRESULT STDMETHODCALLTYPE CFlashUI::GetTypeInfoCount (__RPC__out UINT *pctinfo) {
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE CFlashUI::GetTypeInfo (UINT iTInfo, LCID lcid, __RPC__deref_out_opt ITypeInfo **ppTInfo) {
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE CFlashUI::GetIDsOfNames (__RPC__in REFIID riid, __RPC__in_ecount_full (cNames) LPOLESTR *rgszNames, UINT cNames, LCID lcid, __RPC__out_ecount_full (cNames) DISPID *rgDispId) {
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE CFlashUI::Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) {

		return S_OK;
		switch (dispIdMember) {
		case DISPID_FLASHEVENT_FLASHCALL:
			if (pDispParams->cArgs != 1 || pDispParams->rgvarg[0].vt != VT_BSTR)
				return E_INVALIDARG;
			return this->FlashCall (pDispParams->rgvarg[0].bstrVal);
		case DISPID_FLASHEVENT_FSCOMMAND:
			if (pDispParams && pDispParams->cArgs == 2) {
				if (pDispParams->rgvarg[0].vt == VT_BSTR &&
					pDispParams->rgvarg[1].vt == VT_BSTR) {
					return FSCommand (pDispParams->rgvarg[1].bstrVal, pDispParams->rgvarg[0].bstrVal);
				} else {
					return DISP_E_TYPEMISMATCH;
				}
			} else {
				return DISP_E_BADPARAMCOUNT;
			}
		case DISPID_FLASHEVENT_ONPROGRESS:
			return OnProgress (*pDispParams->rgvarg[0].plVal);
		case DISPID_READYSTATECHANGE:
			return this->OnReadyStateChange (pDispParams->rgvarg[0].lVal);
		}

		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE CFlashUI::QueryInterface (REFIID riid, void **ppvObject) {
		*ppvObject = nullptr;

		if (riid == IID_IUnknown)
			*ppvObject = static_cast</*IOleWindow**/LPUNKNOWN>(this);
		else if (riid == IID_IDispatch)
			*ppvObject = static_cast<IDispatch*>(this);
		else if (riid == __uuidof(_IShockwaveFlashEvents))
			*ppvObject = static_cast<_IShockwaveFlashEvents*>(this);

		if (*ppvObject)
			AddRef ();
		return (!*ppvObject) ? E_NOINTERFACE : S_OK;
	}

	ULONG STDMETHODCALLTYPE CFlashUI::AddRef (void) {
		::InterlockedIncrement (&m_dwRef);
		return m_dwRef;
	}

	ULONG STDMETHODCALLTYPE CFlashUI::Release (void) {
		::InterlockedDecrement (&m_dwRef);
		return m_dwRef;
	}

	HRESULT CFlashUI::OnReadyStateChange (long newState) {
		if (m_pFlashEventHandler) {
			return m_pFlashEventHandler->OnReadyStateChange (newState);
		}
		return S_OK;
	}

	HRESULT CFlashUI::OnProgress (long percentDone) {
		if (m_pFlashEventHandler) {
			return m_pFlashEventHandler->OnProgress (percentDone);
		}
		return S_OK;
	}

	HRESULT CFlashUI::FSCommand (_bstr_t command, _bstr_t args) {
		if (m_pFlashEventHandler) {
			return m_pFlashEventHandler->FSCommand (command, args);
		}
		return S_OK;
	}

	HRESULT CFlashUI::FlashCall (_bstr_t request) {
		if (m_pFlashEventHandler) {
			return m_pFlashEventHandler->FlashCall (request);
		}
		return S_OK;
	}

	void CFlashUI::ReleaseControl () {
		//GetManager()->RemoveTranslateAccelerator(this);
		RegisterEventHandler (FALSE);
		if (m_pFlash) {
			m_pFlash->Release ();
			m_pFlash = nullptr;
		}
	}

	bool CFlashUI::DoCreateControl () {
		if (!CActiveXUI::DoCreateControl ())
			return false;
		//GetManager()->AddTranslateAccelerator(this);
		GetControl (__uuidof(IShockwaveFlash), (LPVOID*) &m_pFlash);
		RegisterEventHandler (TRUE);
		return true;
	}

	void CFlashUI::SetFlashEventHandler (CFlashEventHandler* pHandler) {
		if (m_pFlashEventHandler) {
			m_pFlashEventHandler->Release ();
		}
		if (!pHandler) {
			m_pFlashEventHandler = pHandler;
			return;
		}
		m_pFlashEventHandler = pHandler;
		m_pFlashEventHandler->AddRef ();
	}

	LRESULT CFlashUI::TranslateAccelerator (MSG *pMsg) {
		if (pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST)
			return S_FALSE;

		if (!m_pFlash)
			return E_NOTIMPL;

		// 当前Web窗口不是焦点,不处理加速键
		BOOL bIsChild = FALSE;
		HWND hTempWnd = NULL;
		HWND hWndFocus = ::GetFocus ();

		hTempWnd = hWndFocus;
		while (hTempWnd) {
			if (hTempWnd == m_hwndHost) {
				bIsChild = TRUE;
				break;
			}
			hTempWnd = ::GetParent (hTempWnd);
		}
		if (!bIsChild)
			return S_FALSE;

		CComPtr<IOleInPlaceActiveObject> pObj;
		if (FAILED (m_pFlash->QueryInterface (IID_IOleInPlaceActiveObject, (LPVOID *) &pObj)))
			return S_FALSE;

		HRESULT hResult = pObj->TranslateAccelerator (pMsg);
		return hResult;
	}

	HRESULT CFlashUI::RegisterEventHandler (BOOL inAdvise) {
		if (!m_pFlash)
			return S_FALSE;

		HRESULT hr = S_FALSE;
		CComPtr<IConnectionPointContainer>  pCPC;
		CComPtr<IConnectionPoint> pCP;

		hr = m_pFlash->QueryInterface (IID_IConnectionPointContainer, (void **) &pCPC);
		if (FAILED (hr))
			return hr;
		hr = pCPC->FindConnectionPoint (__uuidof(_IShockwaveFlashEvents), &pCP);
		if (FAILED (hr))
			return hr;

		if (inAdvise) {
			hr = pCP->Advise ((IDispatch*) this, &m_dwCookie);
		} else {
			hr = pCP->Unadvise (m_dwCookie);
		}
		return hr;
	}

};